/* 
 * Copyright (C) 2006 Sasa Coh <sasacoh@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 */

using System.Collections.Generic;

namespace MenuDesigner {

  // handlers - functors - delegates
  public delegate bool VoidDelegate();
  public delegate bool BoolIntDelegate(int keyId);

  /**
  * @class CInputInterface 
  *
  * @brief User input interface declaration
  *
  * @author Sasa Coh
  */
  public interface CInputInterface 
  {
	  /*---------------------------------------
	  * Keyboard event handlers
	  *---------------------------------------*/
    bool onKeyPressed(int keyId);
	  bool onOffHookKey() ;
	  bool onOnHookKey() ;
	  bool onMenuKey() ;
	  bool onEscKey() ;
	  bool onClearKey() ;
	  bool onOkKey();
	  bool onSpeakerKey() ;
	  bool onRedialKey() ;

	  bool onSoftKey(int id) ;
	  bool onFunctionKey(int id) ;
    bool onDigitKey(int id);
    bool onCharKey(int id);

	  bool onLeftKey() ;
	  bool onRightKey() ;
	  bool onUpKey() ;
	  bool onDownKey() ;

	  bool onLongKey(int keyId) ;
  }

  /**
   * @class CComponent
   *
   * @brief CComponent class is an abstract component interface for 
   * recursive composition implementation. It implements CInterface abstract class.
   *
   * @author Sasa Coh
   */
  public abstract class CComponent : CInputInterface
  {
    protected object _tag;						//!< auxiliary member variable to store some user data
    public CComposite _parent;        //!< Pointer to parent component
    private int _componentId = 0;     //!< Defines component identification         
    private int _posX;                //!< Defines component position
    private int _posY;                //!< Defines component position
    private bool _focused = false;    //!< Indicates if component is focused
    private int _linkkeyId = 0;

    public string [] subItems;

    // static member
    protected static CComponentController _controller; //!< static reference to ComponentController
      

    #region Properties
    /*---------------------------------------
     * Common interface properties
     *---------------------------------------*/  
    public virtual int PosX
    {
      get { return _posX; }
      set { _posX = value; }
    }

    public virtual int PosY
    {
      get { return _posY; }
      set 
      { 
        _posY = value;
        _linkkeyId = value;
      }
    }

    public virtual bool Focused
    {
      get { return _focused; }
      set { _focused = value; }
    }

    public virtual int Size
    {
      get { return 1; }
    }
    
    // non virtual properties

    public int Id 
    {
      get { return _componentId; }
      set { _componentId = value; }
    }

    public int LinkKey
    {
      set { _linkkeyId = value; }
      get { return _linkkeyId; }
    }

    #endregion Properties

    #region Events
    /*---------------------------------------
	  * Keyboard events
	  *---------------------------------------*/
    public virtual bool onKeyPressed(int keyId)
    {
      return OnKeyPressed(keyId);
    }
    
    public virtual bool onOffHookKey()
    {
      return Offhook();
    }

    public virtual bool onOnHookKey()
    {
      return Onhook();
    }
    public virtual bool onMenuKey()
    {
      return Menu();
    }
    public virtual bool onEscKey()
    {
      return Esc();
    }
    public virtual bool onClearKey()
    {
      return Clear();
    }
    public virtual bool onOkKey()
    {
      return Ok();
    }
    public virtual bool onSpeakerKey()
    {
      return Speaker();
    }
    public virtual bool onRedialKey()
    {
      return Redial();
    }
    public virtual bool onSoftKey(int id)
    {
      return Softkey(id);
    }
    public virtual bool onFunctionKey(int id)
    {
      return Functionkey(id);
    }
    public virtual bool onDigitKey(int id)
    {
      return Digitkey(id);
    }
    public virtual bool onCharKey(int id)
    {
      return Charkey(id);
    }

    public virtual bool onLeftKey()
    {
      return Left();
    }
    public virtual bool onRightKey()
    {
      return Right();
    }
    public virtual bool onUpKey()
    {
      return Up();
    }
    public virtual bool onDownKey()
    {
      return Down();
    }
    public virtual bool onLongKey(int keyId)
    {
      return LongPress(keyId);
    }

    public virtual bool onLostFocus()
    { 
      return OnLostFocus();
    }


    ////////////////////////////////////////////////////////////////////////////////////
    // Events
    public event VoidDelegate Offhook;
    public event VoidDelegate Onhook;
    public event VoidDelegate Speaker;
    public event VoidDelegate Esc;
    public event VoidDelegate Clear;
    public event VoidDelegate Ok;
    public event VoidDelegate Menu;
    public event VoidDelegate Redial;
    public event VoidDelegate Left;
    public event VoidDelegate Right;
    public event VoidDelegate Up;
    public event VoidDelegate Down;

    public event BoolIntDelegate OnKeyPressed;
    public event BoolIntDelegate Softkey;
    public event BoolIntDelegate Digitkey;
    public event BoolIntDelegate Charkey;
    public event BoolIntDelegate Functionkey;
    public event BoolIntDelegate LongPress;

    // internal events
    public event VoidDelegate OnLostFocus;

    protected bool nullHandler()
    {
      return false;
    }
    protected bool nullHandler(int id)
    {
      return false;
    }

    #endregion Events


    #region Public methods
    /*---------------------------------------
    * Rendering events.
    *---------------------------------------*/
    /**
    * A pure virtual member for render component drawing.
    * @param renderer reference to renderer object.
    */
    public abstract void onDraw(CObserver renderer);  //!< Render component.

    /**
    * A pure virtual member for remove component drawing.
    * @param[in] renderer reference to renderer object.
    */
    public abstract void onErase(CObserver renderer); //!< Erase component.

    public virtual void onEntry() {}   //!< Indicates component to be activated
    public virtual void onExit() {}   //!< Indicates component to be left

    /*---------------------------------------
     * Composite structure
     *---------------------------------------*/
    public virtual void add(CComponent c) { }
    public virtual void insert(CComponent c) { }
    public virtual void remove(CComponent c) { }
    public virtual void removeAll() { }
    public virtual CComponent getChild(int id) { return this; }

    public virtual bool isNull() { return false; }

    //////////////////////////////////////////////////////////////////////////
    // Controller access methods...
    public static CComponentController getController() {return _controller; }

    public static void setController(CComponentController controller) { _controller = controller; }

    #endregion


    #region Constructors
    //!< component constructor   
    protected CComponent(int componentId)
    {
      _controller = CComponentController.getInstance();

      subItems = new string[3];

      this.Id = componentId;

      this.Offhook = this.nullHandler;
      Onhook = this.nullHandler;
      Speaker = this.nullHandler;
      Esc = this.nullHandler;
      Clear = this.nullHandler;
      Ok = this.nullHandler;
      Menu = this.nullHandler;
      Left = this.nullHandler;
      Right = this.nullHandler;
      Up = this.nullHandler;
      Down = this.nullHandler;
      Redial = this.nullHandler;

      Softkey = this.nullHandler;
      Digitkey = this.nullHandler;
      Charkey = this.nullHandler;
      Functionkey = this.nullHandler;
      LongPress = this.nullHandler;

      OnLostFocus = this.nullHandler;
    }

    #endregion  

  }


  /***************************************************************
  * @class CComposite
  *
  * @brief Composition class with component list.
  *
  * @author Sasa Coh
  */
  public abstract class CComposite : CComponent 
  {
    public override int Size
    {
      get { 
        int size = 0;
        foreach (CComponent comp in _components)
        {
          size += comp.Size;
        }
        return size; 
      }
    }

	  /*---------------------------------------
	  * Draw events
	  *---------------------------------------*/
    public override void onDraw(CObserver renderer)
    {
      foreach (CComponent comp in _components)
      {
        comp.onDraw(renderer);
      }
    }
    public override void onErase(CObserver renderer)
    {
      foreach (CComponent comp in _components)
      {
        comp.onErase(renderer);
      }
    }
    public override void onEntry()
    {
      foreach (CComponent comp in _components)
      {
        comp.onEntry();
      }
    }
    public override void onExit()
    {
      foreach (CComponent comp in _components)
      {
        comp.onExit();
      }
    }

    /*---------------------------------------
	  * Keyboard events
	  *---------------------------------------*/
    public override bool onKeyPressed(int keyId)
    {
      base.onKeyPressed(keyId);
      foreach (CComponent comp in _components)
      {
        comp.onKeyPressed(keyId);
      }
      return true;
    }

    public override bool onOffHookKey()
    {
      base.onOffHookKey();
      foreach (CComponent comp in _components)
      {
        comp.onOffHookKey();
      }
      return true;
    }
    public override bool onOnHookKey()
    {
      base.onOnHookKey();
      foreach (CComponent comp in _components)
      {
        comp.onOnHookKey();
      }
      return true;
    }
    public override bool onMenuKey()
    {
      base.onMenuKey();
      foreach (CComponent comp in _components)
      {
        comp.onMenuKey();
      }
      return true;
    }
    public override bool onEscKey()
    {
      bool status = base.onEscKey();
      foreach (CComponent comp in _components)
      {
        status |= comp.onEscKey();
      }
      return status;
    }
    public override bool onClearKey()
    {
      foreach (CComponent comp in _components)
      {
        comp.onClearKey();
      }
      return true;
    }
    public override bool onOkKey()
    {
      base.onOkKey();
      foreach (CComponent comp in _components)
      {
        comp.onOkKey();
      }
      return true;
    }
    public override bool onSpeakerKey()
    {
      foreach (CComponent comp in _components)
      {
        comp.onSpeakerKey();
      }
      return true;
    }
    public override bool onRedialKey()
    {
      foreach (CComponent comp in _components)
      {
        comp.onRedialKey();
      }
      return true;
    }
    public override bool onSoftKey(int id)
    {
      base.onSoftKey(id);

      foreach (CComponent comp in _components)
      {
        // focus handling...
        if (id == comp.LinkKey)
        {
          comp.Focused = true;
        }
        else
        {
          comp.Focused = false;
          // trigger on lost focus event!!!
          comp.onLostFocus();
        }
        // default onSoftKey handler
        bool status = comp.onSoftKey(id);
        if (status == true) return true;
      }
      return true;
    }
    public override bool onFunctionKey(int id)
    {
      foreach (CComponent comp in _components)
      {
        comp.onFunctionKey(id);
      }
      return true;
    }
    public override bool onDigitKey(int id)
    {
      base.onDigitKey(id);
      foreach (CComponent comp in _components)
      {
        comp.onDigitKey(id);
      }
      return true;
    }
    
    public override bool onCharKey(int id)
    {
      base.onCharKey(id);
      foreach (CComponent comp in _components)
      {
        comp.onCharKey(id);
      }
      return true;
    }
    public override bool onLeftKey()
    {
      foreach (CComponent comp in _components)
      {
        comp.onLeftKey();
      }
      return true;
    }
    public override bool onRightKey()
    {
      foreach (CComponent comp in _components)
      {
        comp.onRightKey();
      }
      return true;
    }
    public override bool onUpKey()
    {
      foreach (CComponent comp in _components)
      {
        comp.onUpKey();
      }
      return true;
    }
    public override bool onDownKey()
    {
      foreach (CComponent comp in _components)
      {
        comp.onDownKey();
      }
      return true;
    }
	  /*---------------------------------------
	  * Composite structure
	  *---------------------------------------*/
    public override void add(CComponent component)
    {
      //int pos = getFreePosition();
      //if (pos == -1) component.Pos = pos;
      component._parent = this;
      _components.Add(component);
    }
/*    public override void insert(CComponent component, int position)
    {
      _components.add(component);
      component.Pos = position;
    }*/
    public override void remove(CComponent component)
    {
      _components.Remove(component);
    }
    public override void removeAll()
    {
      _components.Clear();
    }

    public override CComponent getChild(int id)
    {
      return null;
    }

  	/// <summary>
  	/// CComposite contruction
  	/// </summary>
  	/// <param name="component_id"></param>
    protected CComposite(int component_id)
      : base(component_id)
    {
      _components = new List<CComponent>(); 
    }

    protected int getFreePosition()
    {
      int max = PosY - 1;
      foreach (CComponent comp in _components) 
      {
        if (comp.PosY > max) max = comp.PosY;
      }
      return max+1;
    }

    public List<CComponent> getList()
    {
      return _components;
    }

	  protected List<CComponent> _components;    //!< Composition list contains components
  }

  /**
   * @class CDecorator
   *
   * @brief Component decorator class. Decorating embedded object.
   *
   * @author Sasa Coh
   */
  public abstract class CDecorator : CComponent 
  {
    public override int PosX
    {
      get { return _component.PosX; }
      set { _component.PosX = value; }
    }
    public override int PosY
    {
      get { return _component.PosY; }
      set { _component.PosY = value; }
    }

    public override bool Focused
    {
      get { return _component.Focused; }
      set { _component.Focused = value; }
    }

    public override int Size
    {
      get { return _component.Size; }
    }

    /*---------------------------------------
     * Draw events.
     *---------------------------------------*/
    public override void onDraw(CObserver renderer)
    {
      _component.onDraw(renderer);
    }
    public override void onErase(CObserver renderer)
    {
      _component.onErase(renderer);
    }

    public override void onEntry()
    {
      _component.onEntry();
    }
    public override void onExit()
    {
      _component.onExit();
    }

    /*---------------------------------------
     * Keyboard events
     *---------------------------------------*/
    public override bool onKeyPressed(int keyId)
    {
      return _component.onKeyPressed(keyId);
    }
    public override bool onOffHookKey()
    {
      return _component.onOffHookKey();
    }
    public override bool onOnHookKey()
    {
      return _component.onOnHookKey();
    }
    public override bool onMenuKey()
    {
      return _component.onMenuKey();
    }
    public override bool onEscKey()
    {
      return _component.onEscKey();
    }
    public override bool onClearKey()
    {
      return _component.onClearKey();
    }
    public override bool onOkKey()
    {
      return _component.onOkKey();
    }
    public override bool onSpeakerKey()
    {
      return _component.onSpeakerKey();
    }
    public override bool onRedialKey()
    {
      return _component.onRedialKey();
    }

    public override bool onSoftKey(int id)
    {
      return _component.onSoftKey(id);
    }
    public override bool onFunctionKey(int id)
    {
      return _component.onFunctionKey(id);
    }
    public override bool onDigitKey(int id)
    {
      return _component.onDigitKey(id);
    }
    
    public override bool onCharKey(int id)
    {
      return _component.onCharKey(id);
    }

    public override bool onLeftKey()
    {
      return _component.onLeftKey();
    }
    public override bool onRightKey()
    {
      return _component.onRightKey();
    }
    public override bool onUpKey()
    {
      return _component.onUpKey();
    }
    public override bool onDownKey()
    {
      return _component.onDownKey();
    }

	  /*---------------------------------------
	  * Composite structure
	  *---------------------------------------*/
    public override void add(CComponent c)
    {
      _component.add(c);
    }
    public override void insert(CComponent c)
    {
      _component.insert(c);
    }
    public override void remove(CComponent c)
    {
      _component.remove(c);
    }
    public override void removeAll()
    {
      _component.removeAll();
    }

    /// <summary>
    /// Decorator construction
    /// </summary>
    /// <param name="component"></param>
    protected CDecorator(CComponent component) 
      : base(0) 
    {
      _component = component;
    }

    protected CComponent _component;
  }

  /**
   * @class CNullComponent
   *
   * @brief Null pattern component class.
   *
   * @author Sasa Coh
   */
  public class CNullComponent : CComponent {

    public static CNullComponent instance()
    {
      if (_instance != null)
      {
        _instance = new CNullComponent();
      }
      return _instance;
    }

    public override void onDraw(CObserver renderer)
    {
    }
    public override void onErase(CObserver renderer)
    {
    }
    public override bool isNull() { return true; }
    
    protected CNullComponent() 
      : base(0) 
    {
    }

    private static CNullComponent _instance;
  }

} // namespace MenuDesigner
